#coding:gbk
import requests
import time
from typing import Dict, Any
from datetime import datetime
from collections import deque

# 本文件用于在qmt中调用服务器端的api
# ====== 全局状态（QMT 安全）======
_strategy_initialized = False
_polling_active = False
_processed_order_ids = deque(maxlen=500)

# 配置
SERVER_URL = "http://widechaos.cn/api/quant"
CLIENT_ID = "qmt"
SECRET_KEY = "your_secret_key_here"
ORDER_VOLUME_RATIO = 1.0

_last_order_received_at = 0.0
_empty_poll_streak = 0
_WAIT_ACTIVE_SECONDS = 3
_WAIT_IDLE_SECONDS = 25
_MAX_FOLLOW_UP_BATCH = 3


def _print(msg: str, level: str = "INFO"):
    """统一日志格式：使用全角括号【】，并标注日志级别"""
    timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    print(f"【{timestamp}】[{level}] {msg}")


def _poll_orders(context):
    """轮询服务器获取订单（带本地去重）"""
    global _polling_active, _last_order_received_at, _empty_poll_streak
    
    if _polling_active:
        _print("上次轮询尚未完成，跳过本次轮询", "DEBUG")
        return
        
    _polling_active = True
    _print("开始轮询服务器订单...", "DEBUG")
    _print("────────────── 轮询请求 ──────────────", "DEBUG")
    
    try:
        now = time.time()
        recent = (_last_order_received_at > 0 and (now - _last_order_received_at) < 30)
        wait_seconds = _WAIT_ACTIVE_SECONDS if recent else _WAIT_IDLE_SECONDS
        timeout_seconds = wait_seconds + 5
        response = requests.post(
            f"{SERVER_URL}/qmt_poll",
            json={
                'client_id': CLIENT_ID,
                'key': SECRET_KEY,
                'wait': wait_seconds
            },
            timeout=timeout_seconds,
            headers={"Authorization": f"Bearer {SECRET_KEY}"}
        )

        if response.status_code == 200:
            result = response.json()
            _print(f"服务器响应内容：{result}", "DEBUG")
            
            if result.get('status') == 'success' and result.get('order'):
                order_data = result['order']
                order_id = order_data.get('timestamp')
                if order_id:
                    if order_id in _processed_order_ids:
                        _print(f"重复订单（已处理过），跳过执行：{order_id}", "DEBUG")
                    else:
                        _processed_order_ids.append(order_id)
                        _print(f"收到新订单：{order_data}", "INFO")
                        _execute_order(context, order_data)
                        _last_order_received_at = time.time()
                        for _ in range(_MAX_FOLLOW_UP_BATCH - 1):
                            try:
                                follow = requests.post(
                                    f"{SERVER_URL}/qmt_poll",
                                    json={
                                        'client_id': CLIENT_ID,
                                        'key': SECRET_KEY,
                                        'wait': 0
                                    },
                                    timeout=5
                                )
                                if follow.status_code == 200:
                                    r2 = follow.json()
                                    if r2.get('status') == 'success' and r2.get('order'):
                                        od2 = r2['order']
                                        oid2 = od2.get('timestamp')
                                        if oid2 and oid2 in _processed_order_ids:
                                            _print(f"重复订单（已处理过），跳过执行：{oid2}", "DEBUG")
                                            continue
                                        if oid2:
                                            _processed_order_ids.append(oid2)
                                        _print(f"收到后续订单：{od2}", "INFO")
                                        _execute_order(context, od2)
                                        _last_order_received_at = time.time()
                                        continue
                                    break
                                else:
                                    break
                            except Exception as e:
                                _print(f"? 后续轮询异常：{e}", "ERROR")
                                break
                else:
                    # 无有效ID仍执行，但记录日志
                    _print(f"收到无ID订单，谨慎执行：{order_data}", "WARNING")
                    _execute_order(context, order_data)
            else:
                _print("当前无待处理订单。", "DEBUG")
                _empty_poll_streak += 1
        else:
            _print(f"?? 轮询失败，HTTP 状态码：{response.status_code}", "WARNING")

    except Exception as e:
        _print(f"? 轮询过程中发生异常：{e}", "ERROR")
    finally:
        _polling_active = False
        _print("────────────── 轮询结束 ──────────────", "DEBUG")


def _poll_timer_legacy(context):
    """旧版定时器回调函数（保留但不使用），统一改为调用 _poll_orders"""
    _print("定时器触发轮询(legacy)", "DEBUG")
    _poll_orders(context)


def _execute_order(context, order_data: Dict[str, Any]):
    _print("────────────── 开始执行订单 ──────────────", "INFO")
    
    try:
        order_info = order_data.get('order', {})
        symbol = order_info.get('orderCode', '')
        volume = order_info.get('volume', 0)
        timestamp = order_data.get('timestamp', 'N/A')
        
        _print(f"解析订单信息 - 代码：{symbol}，数量：{volume}，时间戳：{timestamp}", "INFO")
        
        if not symbol or volume == 0:
            _print(f"?? 订单数据无效，跳过执行：{order_info}", "WARNING")
            return

        # 构造股票代码（6开头为SH，否则SZ）
        stock_code = f"{symbol}.SH" if symbol.startswith('6') else f"{symbol}.SZ"
        actual_volume = int(abs(volume) * ORDER_VOLUME_RATIO)
        
        if actual_volume == 0:
            _print(f"?? 按比例缩放后交易数量为零，跳过订单：{symbol}", "WARNING")
            return

        # 获取账号ID
        account_id = context.account_id
        _print(f"使用交易账户：{account_id}", "INFO")

        # 确定买卖方向：正数买入，负数卖出
        shares = actual_volume if volume > 0 else -actual_volume
        direction = "买入" if volume > 0 else "卖出"
        _print(f"准备{direction}股票：{stock_code}，数量：{shares}", "INFO")

        # 调用 QMT 官方下单函数
        bp = globals().get('buy_price', None)
        sp = globals().get('sell_price', None)
        if direction == '买入':
            style = _resolve_style(True, bp)
            use_algo = (style is None)
        else:
            style = _resolve_style(False, sp)
            use_algo = (style is None)
        if use_algo:
            result = _algo_place(stock_code, shares, account_id, direction)
        else:
            if style:
                result = order_shares(stock_code, shares, style, context, account_id)
            else:
                result = order_shares(stock_code, shares, context, account_id)
        _print(f"下单结果：{result}", "INFO")

        _send_confirmation(order_data, 'executed')

    except Exception as e:
        _print(f"? 订单执行失败：{e}", "ERROR")
        _send_confirmation(order_data, 'failed')
    finally:
        _print("────────────── 订单执行结束 ──────────────", "INFO")

def _resolve_style(is_buy: bool, choice: Any):
    s = str(choice or '').strip()
    if not s:
        return 'LATEST'
    if '算法交易' in s:
        return None
    if is_buy:
        if s == '卖5价':
            return 'SALE5'
        if s == '卖4价':
            return 'SALE4'
        if s == '卖3价':
            return 'SALE3'
        if s == '卖2价':
            return 'SALE2'
        if s == '卖1价':
            return 'SALE1'
    else:
        if s == '买5价':
            return 'BUY5'
        if s == '买4价':
            return 'BUY4'
        if s == '买3价':
            return 'BUY3'
        if s == '买2价':
            return 'BUY2'
        if s == '买1价':
            return 'BUY1'
    if s == '对手价':
        return 'COMPETE'
    if s == '最新价' or s.lower() == 'latest':
        return 'LATEST'
    return 'LATEST'

def _algo_place(stock_code: str, shares: int, account_id: str, direction: str):
    try:
        op = 23 if shares > 0 else 24
        order_type = 1101
        pr_type = -1
        model_price = -1
        vol = abs(shares)
        strat = 'relay'
        qt_raw = globals().get('quickTrade', '是(1)')
        qt = 1 if str(qt_raw).strip() in ['是(1)', '1', '是'] else (2 if str(qt_raw).strip() in ['是(2)', '2'] else 0)
        interval = int(float(str(globals().get('algoPlaceInterval', 3))))
        max_secs = int(float(str(globals().get('algoMaxSeconds', 60))))
        max_count = max(1, max_secs // max(interval, 1))
        userparam = {
            'OrderType': 1,
            'MaxOrderCount': max_count,
            'PlaceOrderInterval': interval,
            'PriceType': 14
        }
        return algo_passorder(op, order_type, account_id, stock_code, pr_type, model_price, vol, strat, qt, 'algo', userparam, ContextInfo)
    except Exception as e:
        return {'error': str(e)}


def _send_confirmation(order_data: Dict[str, Any], status: str):
    _print(f"发送订单确认消息，状态：{status}", "DEBUG")
    
    try:
        order_timestamp = order_data.get('timestamp', datetime.now().isoformat())
        confirm_data = {
            'client_id': CLIENT_ID,
            'order_id': order_timestamp,
            'status': status,
            'tunnelId': None
        }
        _print(f"确认数据：{confirm_data}", "DEBUG")
        response = requests.post(
            f"{SERVER_URL}/qmt_confirm",
            json=confirm_data,
            timeout=5,
            headers={"Authorization": f"Bearer {SECRET_KEY}"}
        )
        if response.status_code == 200:
            _print("? 订单确认已成功发送。", "DEBUG")
        else:
            _print(f"?? 订单确认发送失败，状态码：{response.status_code}", "WARNING")
    except Exception as e:
        _print(f"?? 发送确认消息时发生异常：{e}", "WARNING")


# ====== QMT 入口函数（标准命名）======

def init(context):
    global _strategy_initialized
    _print("?? 启动 QMT 自动中继策略...", "INFO")
    _print("────────────── 初始化开始 ──────────────", "INFO")
    
    # 初始化全局状态
    _strategy_initialized = True
    try:
        context.account_id = str(globals().get('accountID', context.account_id if hasattr(context, 'account_id') else '88880'))
    except Exception:
        context.account_id = '88880'
    try:
        globals()['SERVER_URL'] = str(globals().get('serverURL', SERVER_URL))
        globals()['CLIENT_ID'] = str(globals().get('clientID', CLIENT_ID))
        globals()['SECRET_KEY'] = str(globals().get('keyID', SECRET_KEY))
        globals()['TUNNEL_ID'] = str(globals().get('tunnelId', TUNNEL_ID))
        globals()['ORDER_VOLUME_RATIO'] = float(str(globals().get('jquant_qmt_r', ORDER_VOLUME_RATIO)))
    except Exception:
        pass
    _print(f"已设置默认交易账户 ID：{context.account_id}", "INFO")
    
    # 设置定时器 - 每1秒轮询一次
    # 方法1: 使用 run_time (推荐，简单直接)
    context.run_time("_poll_timer", "1nSecond", "2000-01-01 00:00:00")
    _print("? 已设置定时器：每1秒触发轮询一次（结合长轮询，空转几乎为零）", "INFO")
    
    # 或者方法2: 使用 schedule_run (更灵活)
    # import datetime as dt
    # now = datetime.now()
    # start_time = now.strftime('%Y%m%d%H%M%S')
    # context.schedule_run(_poll_timer, start_time, -1, dt.timedelta(seconds=1), 'poll_timer')
    # _print("? 已设置定时器：每1秒轮询一次 (schedule_run)", "INFO")
    
    _print("? 策略初始化完成。", "INFO")
    _print("────────────── 初始化结束 ──────────────", "INFO")


def handlebar(context):
    """QMT 每根K线回调函数 - 保留但不再用于轮询"""
    # 注意：由于我们使用了定时器，这里可以留空或用于其他目的
    # 原来的时间间隔逻辑已移除
    pass


def _poll_timer(context):
    """定时器回调函数 - 统一调用 _poll_orders，避免重复实现"""
    _poll_orders(context)
